(function () { const M = (DO.internal.app = DO.internal.app || {}); const leaveHooks = {}; DO.lifecycle = { onLeave: function (viewId, fn) { (leaveHooks[viewId] = leaveHooks[viewId] || []).push(fn); }, run: function (viewId) { const list = leaveHooks[viewId] || []; leaveHooks[viewId] = []; list.forEach(function (fn) { try{ fn(); }catch (e) { DO.log.debug("core/app/lifecycle", e); } }); } }; // Roots emptied when the user leaves a page (null = the view container itself is the root). const UNMOUNT = { viewCategories: "categoriesRoot", viewCategoryProducts: "catProductsRoot", viewFlash: "flashRoot", viewProduct: "productRoot", viewWishlist: "wishlistRoot", viewLegal: "legalRoot", viewSuccess: "successRoot", viewCheckout: null, viewOrders: null, viewAddresses: null, viewEditProfile: null, viewChangePassword: null, viewLogin: null, viewRegister: null, viewAccount: null }; // true only while that page is the one on screen (async work must check this before drawing) M.viewActive = function (viewId) { const v = document.getElementById(viewId); return !!v && v.style.display !== "none"; }; const generation = {}; DO.lifecycle.guard = function (viewId) { const mine = generation[viewId] || 0; return function stale() { return (generation[viewId] || 0) !== mine || !M.viewActive(viewId); }; }; M.unmountView = function (viewId) { if (!(viewId in UNMOUNT)) return; generation[viewId] = (generation[viewId] || 0) + 1; DO.lifecycle.run(viewId); if (viewId === "viewCategoryProducts") M.cleanupCategoryIO(); const root = document.getElementById(UNMOUNT[viewId] || viewId); if (!root) return; if (viewId === "viewCategories") { root.dataset.loaded = ""; root.dataset.catsOk = "0"; } root.innerHTML = ""; }; function trackPageView(view, params){ try{ DO.app.trackEvent && DO.app.trackEvent("page_view", { page_location: location.href, page_path: location.pathname, page_title: document.title || "Abyat Shop", view: String(view || ""), cat: params?.cat != null ? String(params.cat) : undefined, product: params?.product != null ? String(params.product) : undefined, q: params?.q != null ? String(params.q) : undefined }); }catch (e) { DO.log.debug("core/app/trackPageView", e); } } M.ROUTES = { home: { viewId: "viewHome", nav: "home", enter: async () => { await DO.pages.home.mount(); M.CartBadges.applyWhenCardsAppear(1500); M.CartBadges.applyToVisible(); }, leave: () => { DO.pages.home.unmount(); } }, wishlist: { viewId: "viewWishlist", nav: "account", enter: async () => { if (!DO.state.wishlistLoaded) { await M.loadScript("/do/assets/js/pages/wishlist.js"); DO.state.wishlistLoaded = true; } if (M.viewActive("viewWishlist") && typeof DO.pages.wishlist.render === "function") DO.pages.wishlist.render(); M.CartBadges.applyWhenCardsAppear(1200); } }, categories: { viewId: "viewCategories", nav: "categories", enter: async () => { const root = document.getElementById("categoriesRoot"); if (!root || typeof DO.pages.categories.load !== "function") { M.CartBadges.applyWhenCardsAppear(1200); return; } if (root.dataset.loaded !== "1") { if (!M.__categoriesEnterPromise) { M.__categoriesEnterPromise = (async () => { await DO.pages.categories.load(); if (root.dataset.catsOk === "1") { root.dataset.loaded = "1"; } else { root.dataset.loaded = ""; } })().finally(() => { M.__categoriesEnterPromise = null; }); } await M.__categoriesEnterPromise; } M.CartBadges.applyWhenCardsAppear(1200); } }, category: { viewId: "viewCategoryProducts", nav: "categories", enter: async (r) => { if (r.cat) await DO.app.showCategoryProducts(r.cat, false, r.seo_url || r.seo || ""); } }, product: { viewId: "viewProduct", nav: "categories", enter: async (r) => { if (!r.product) return; M.cleanupCategoryIO(); // منطلق ViewContent فورًا من product_id الموجود أصلاً بالرابط، قبل ما ننتظر // بيانات المنتج الكاملة توصل من الـ API. فيسبوك محتاج بس content_ids لهالحدث، // فما في داعي نأخر إرساله لحد ما تخلص صفحة المنتج تحميلها بالكامل — تأخير كان // عم يخسرنا أحداث حقيقية لما الزائر يطلع بسرعة (خصوصًا جايين من إعلان). try{ DO.app.trackEvent && DO.app.trackEvent("view_item", { items: [{ item_id: String(r.product) }], page_location: location.href, page_path: location.pathname }); }catch (e) { DO.log.debug("core/app/enter", e); } if (typeof DO.product.show === "function") { await DO.product.show(String(r.product), false); } else { console.warn("showProduct غير موجودة بعد"); } M.CartBadges.applyWhenCardsAppear(900); } }, search_home: { viewId: "viewSearch", nav: "categories", enter: async () => { if (!DO.state.searchLoaded) { await M.loadScripts(["/do/assets/js/pages/search/helpers.js","/do/assets/js/pages/search/recent.js","/do/assets/js/pages/search/shimmer.js","/do/assets/js/pages/search/scaffold.js","/do/assets/js/pages/search/api.js","/do/assets/js/pages/search/trending.js","/do/assets/js/pages/search/page.js"]); DO.state.searchLoaded = true; } DO.pages.search.cleanupIO?.(); if (typeof DO.pages.search.renderHome === "function") { await DO.pages.search.renderHome({ limit: 12, days: 30 }); } else { const root = document.getElementById("viewSearch"); if (root){ root.innerHTML = `

Search

Loading...
`; } } M.CartBadges.applyWhenCardsAppear(900); M.CartBadges.applyToVisible(); } }, search: { viewId: "viewSearch", nav: "categories", enter: async (r) => { const q = String(r.q || "").trim(); if (!q) return; if (!DO.state.searchLoaded) { await M.loadScripts(["/do/assets/js/pages/search/helpers.js","/do/assets/js/pages/search/recent.js","/do/assets/js/pages/search/shimmer.js","/do/assets/js/pages/search/scaffold.js","/do/assets/js/pages/search/api.js","/do/assets/js/pages/search/trending.js","/do/assets/js/pages/search/page.js"]); DO.state.searchLoaded = true; } let mount = document.getElementById("searchResultsRoot"); if (!mount) { let root = document.getElementById("searchRoot"); if (!root) { root = document.createElement("div"); root.id = "searchRoot"; const view = document.getElementById("viewSearch"); if (view) view.appendChild(root); } mount = document.createElement("div"); mount.id = "searchResultsRoot"; root.appendChild(mount); } try{ DO.app.trackEvent && DO.app.trackEvent("search", { search_term: q, q, page_location: location.href, page_path: location.pathname }); }catch (e) { DO.log.debug("core/app/enter", e); } DO.pages.search.cleanupIO?.(); await DO.pages.search.show(q, false, { mountId: "searchResultsRoot" }); M.CartBadges.applyWhenCardsAppear(1200); M.CartBadges.applyToVisible(); } }, cart: { viewId: "viewCart", nav: "cart", enter: async () => { if (typeof DO.pages.cart.load === "function") { await DO.pages.cart.load(); } else if (typeof window.loadCart === "function") { await window.loadCart(); } else { console.warn("cart.js مش عامل loadCartUI أو loadCart"); } await M.CartBadges.sync(true); }, leave: () => { if (typeof DO.pages.cart.unmount === "function") DO.pages.cart.unmount(); } }, login: { viewId: "viewLogin", nav: "account", enter: async () => { if (!DO.state.loginLoaded) { await M.loadScript("/do/assets/js/pages/account/login.js"); DO.state.loginLoaded = true; } M.viewActive("viewLogin") && DO.pages.login.render && DO.pages.login.render(); } }, register: { viewId: "viewRegister", nav: "account", enter: async () => { if (!DO.state.registerLoaded) { await M.loadScript("/do/assets/js/pages/account/register.js"); DO.state.registerLoaded = true; } M.viewActive("viewRegister") && DO.pages.register.render && DO.pages.register.render(); } }, return: { viewId: "viewLegal", nav: "account", enter: async () => { await M.loadCss("/do/assets/css/pages/legal.css"); await M.loadScript("/do/assets/js/pages/legal.js"); M.viewActive("viewLegal") && DO.pages.legal.render && DO.pages.legal.render("return"); } }, privacy: { viewId: "viewLegal", nav: "account", enter: async () => { await M.loadCss("/do/assets/css/pages/legal.css"); await M.loadScript("/do/assets/js/pages/legal.js"); M.viewActive("viewLegal") && DO.pages.legal.render && DO.pages.legal.render("privacy"); } }, terms: { viewId: "viewLegal", nav: "account", enter: async () => { await M.loadCss("/do/assets/css/pages/legal.css"); await M.loadScript("/do/assets/js/pages/legal.js"); M.viewActive("viewLegal") && DO.pages.legal.render && DO.pages.legal.render("terms"); } }, checkout: { viewId: "viewCheckout", nav: "cart", enter: async () => { if (!DO.state.checkoutLoaded) { await M.loadScripts(["/do/assets/js/pages/checkout/helpers.js","/do/assets/js/pages/checkout/tracking.js","/do/assets/js/pages/checkout/api.js","/do/assets/js/pages/checkout/skeleton.js","/do/assets/js/pages/checkout/address.js","/do/assets/js/pages/checkout/summary.js","/do/assets/js/pages/checkout/picker.js","/do/assets/js/pages/checkout/page.js"]); await M.loadCss("/do/assets/css/pages/checkout.css"); DO.state.checkoutLoaded = true; } M.viewActive("viewCheckout") && DO.pages.checkout.render && DO.pages.checkout.render(); } }, orders: { viewId: "viewOrders", nav: "account", enter: async () => { if (!DO.state.ordersLoaded) { await M.loadScript("/do/assets/js/pages/account/orders.js"); DO.state.ordersLoaded = true; } M.viewActive("viewOrders") && DO.pages.orders.render && DO.pages.orders.render(); } }, addresses: { viewId: "viewAddresses", nav: "account", enter: async () => { if (!DO.state.addressesLoaded) { await M.loadScript("/do/assets/js/pages/account/addresses.js"); DO.state.addressesLoaded = true; } M.viewActive("viewAddresses") && DO.pages.addresses.render && DO.pages.addresses.render(); } }, edit_profile: { viewId: "viewEditProfile", nav: "account", enter: async () => { if (!DO.state.editProfileLoaded) { await M.loadScript("/do/assets/js/pages/account/edit-profile.js"); DO.state.editProfileLoaded = true; } M.viewActive("viewEditProfile") && DO.pages.editProfile.render && DO.pages.editProfile.render(); } }, change_password: { viewId: "viewChangePassword", nav: "account", enter: async () => { if (!DO.state.changePasswordLoaded) { await M.loadScript("/do/assets/js/pages/account/change-password.js"); DO.state.changePasswordLoaded = true; } M.viewActive("viewChangePassword") && DO.pages.changePassword.render && DO.pages.changePassword.render(); } }, flash: { viewId: "viewFlash", nav: "flash", enter: async () => { if (!DO.state.flashLoaded) { await M.loadScripts(["/do/assets/js/pages/flash/helpers.js","/do/assets/js/pages/flash/styles.js","/do/assets/js/pages/flash/api.js","/do/assets/js/pages/flash/modules.js","/do/assets/js/pages/flash/slider.js","/do/assets/js/pages/flash/page.js"]); DO.state.flashLoaded = true; } if (M.viewActive("viewFlash") && typeof DO.pages.flash.render === "function") DO.pages.flash.render(); } }, success: { viewId: "viewSuccess", nav: "cart", enter: async () => { if (!DO.state.successLoaded){ await M.loadCss("/do/assets/css/pages/success.css"); await M.loadScript("/do/assets/js/pages/success.js"); DO.state.successLoaded = true; } M.viewActive("viewSuccess") && DO.pages.success.render && DO.pages.success.render(); } }, account: { viewId: "viewAccount", nav: "account", enter: async () => { M.viewActive("viewAccount") && DO.pages.account.render && DO.pages.account.render(); } }, }; // Bumped at the start of every go() call. If a SECOND call starts and finishes while an EARLIER one is // still waiting (e.g. on DO.css.forRoute, or the SEO lookup below), the earlier one must not go on to // call route.enter() once its wait ends — otherwise a slow first navigation can resume after a faster // second one already finished, and silently overwrite whatever the user is now actually looking at. // This is a real race (confirmed: rapid back-and-forth between two products within ~2s triggers it), // not specific to any one page type, so the guard lives here rather than duplicated per route. let navGen = 0; async function go(view, params={}, push=true){ const myNavGen = ++navGen; const stale = () => myNavGen !== navGen; const r = { view, ...params }; if (push){ if (view === "home") M.setPath("/"); else if (view === "categories") M.setPath("/categories"); else if (view === "cart") M.setPath("/cart"); else if (view === "account") M.setPath("/account"); else if (view === "privacy") M.setPath("/privacy"); else if (view === "terms") M.setPath("/terms"); else if (view === "return") M.setPath("/return"); else if (view === "flash") M.setPath("/flash"); else if (view === "wishlist") M.setPath("/wishlist"); else if (view === "login") M.setPath("/login"); else if (view === "register") M.setPath("/register"); else if (view === "orders") M.setPath("/orders"); else if (view === "addresses") M.setPath("/addresses"); else if (view === "edit_profile") M.setPath("/edit-profile"); else if (view === "change_password") M.setPath("/change-password"); else if (view === "checkout") M.setPath("/checkout"); else if (view === "success") M.setPath("/success"); else if (view === "search") { const q = String(params.q || "").trim(); if (q) M.setPath("/search/" + M.encodeSeg(q)); else M.setPath("/search"); } else if (view === "search_home") { M.setPath("/search"); } else if (view === "category") { let seoPath = params.seo_url || params.seo || ""; if (!seoPath && params.cat != null){ try{ const rr = await DO.api.fetch(`/index.php?route=extension/mstore/seo&category_id=${encodeURIComponent(params.cat)}`); if (stale()) return; // a newer navigation has already taken over; don't set the URL for this one seoPath = rr?.seo_url || (rr?.keyword ? ("/" + String(rr.keyword).replace(/^\/+/, "")) : ""); }catch (e) { DO.log.warn("core/app/go", e); } } if (seoPath && String(seoPath).startsWith("/")) M.setPath(String(seoPath)); else if (seoPath) M.setPath("/" + String(seoPath).replace(/^\/+/, "")); else M.setPath("/category/" + M.encodeSeg(params.cat || "")); } else if (view === "product"){ let seoPath = params.seo_url || params.seo || ""; if (!seoPath && params.product != null){ try{ const rr = await DO.api.fetch(`/index.php?route=extension/mstore/seo&product_id=${encodeURIComponent(params.product)}`); if (stale()) return; // a newer navigation has already taken over; don't set the URL for this one seoPath = rr?.seo_url || (rr?.keyword ? ("/" + String(rr.keyword).replace(/^\/+/, "")) : ""); }catch (e) { DO.log.warn("core/app/go", e); } } if (seoPath && String(seoPath).startsWith("/")) M.setPath(String(seoPath)); else if (seoPath) M.setPath("/" + String(seoPath).replace(/^\/+/, "")); else M.setPath("/product/" + M.encodeSeg(params.product || "")); } else M.setPath("/"); } const route = M.ROUTES[view] || M.ROUTES.home; // Switch away from the page being left BEFORE awaiting anything (CSS for the new route can take a // moment, even from cache). Otherwise the OLD page stays fully visible for that whole wait, which on a // real device reads as "it shows the page I'm leaving for a moment" before the new one appears. const prevView = DO.state.DO_ROUTE && DO.state.DO_ROUTE.view; if (prevView && prevView !== view) { const prev = M.ROUTES[prevView]; if (prev && typeof prev.leave === "function") { try{ prev.leave(); }catch (e) { DO.log.warn("core/app/leave", e); } } if (prev && prev.viewId !== route.viewId) M.unmountView(prev.viewId); } M.showView(route.viewId); M.setActiveNav(route.nav); M.setBodyViewClass(view); // Product-to-product is a same-view transition (view stays "product" both times), so the generic // leave/unmount block above never runs for it. Without this, the OLD product's fully rendered page // stays fully visible — not just briefly, but for as long as the CSS-loading await below takes — until // showProductImpl's own renderSkeleton() finally clears it, which only happens afterward. Clearing it // to a skeleton right here, before that wait, is what actually fixes the "shows the page I'm leaving" // flash for Back/Next between two products specifically. if (view === "product" && prevView === "product"){ try{ DO.internal.product.renderSkeleton?.(document.getElementById("productRoot")); } catch (e) { DO.log.debug("core/app/go", e); } } await DO.css.forRoute(view); // The most important check: this wait is exactly where a slow navigation can lag behind a faster, // later one. If a newer go() has started since, that one already showed its own view and will finish // on its own — this older call must stop here rather than go on to call route.enter() and overwrite // whatever the user is now actually looking at with stale data for the page they already left. if (stale()) return; if (push) { M.Scroll.resetTop(); M.Scroll.settleTop(1200); } DO.state.DO_ROUTE = Object.assign({}, r, { view: view, cat: (view === "category" ? String(r.cat || "") : undefined), product: (view === "product" ? String(r.product || "") : undefined), q: (view === "search" ? String(r.q || "") : undefined) }); try{ window.dispatchEvent(new CustomEvent("do:route", { detail: DO.state.DO_ROUTE })); }catch (e) { DO.log.debug("core/app/go", e); } trackPageView(view, DO.state.DO_ROUTE); await route.enter(r); M.CartBadges.applyToVisible(); M.CartBadges.applyWhenCardsAppear(900); } async function handleRoute(){ M.cleanupCategoryIO(); const parsed = M.parseRouteFromPath(); if (parsed.kind === "seo"){ if (parsed.slug === "success") return go("success", {}, false); if (parsed.slug === "privacy") return go("privacy", {}, false); if (parsed.slug === "terms") return go("terms", {}, false); if (parsed.slug === "return") return go("return", {}, false); if (parsed.slug === "cart") return go("cart", {}, false); if (parsed.slug === "account") return go("account", {}, false); if (parsed.slug === "categories") return go("categories", {}, false); if (parsed.slug === "flash") return go("flash", {}, false); if (parsed.slug === "wishlist") return go("wishlist", {}, false); if (parsed.slug === "checkout") return go("checkout", {}, false); if (parsed.slug === "login") return go("login", {}, false); if (parsed.slug === "register") return go("register", {}, false); if (parsed.slug === "orders") return go("orders", {}, false); if (parsed.slug === "addresses") return go("addresses", {}, false); if (parsed.slug === "edit-profile") return go("edit_profile", {}, false); if (parsed.slug === "change-password") return go("change_password", {}, false); if (parsed.slug.startsWith("search/")){ const q = M.decodeSeg(parsed.slug.split("/").slice(1).join("/")); return go("search", { q }, false); } if (parsed.slug.startsWith("category/")){ const id = M.decodeSeg(parsed.slug.split("/").slice(1).join("/")); return go("category", { cat:id }, false); } if (parsed.slug.startsWith("product/")){ const id = M.decodeSeg(parsed.slug.split("/").slice(1).join("/")); return go("product", { product:id }, false); } const seo = await M.resolveSeoSlugToTarget(parsed.slug); if (seo){ if (seo.type === "product"){ return go("product", { product: String(seo.id), seo: "/" + parsed.slug }, false); } if (seo.type === "category"){ const seoUrl = "/" + parsed.slug; M.CatSEO.set(String(seo.id), seoUrl); return go("category", { cat: String(seo.id), seo_url: seoUrl, path: String(seo.path || "") }, false); } } return go("home", {}, false); } const v = parsed.view; const p = parsed.params || {}; if (v === "home") return go("home", {}, false); if (v === "categories") return go("categories", {}, false); if (v === "cart") return go("cart", {}, false); if (v === "account") return go("account", {}, false); if (v === "flash") return go("flash", {}, false); if (v === "wishlist") return go("wishlist", {}, false); if (v === "login") return go("login", {}, false); if (v === "register") return go("register", {}, false); if (v === "orders") return go("orders", {}, false); if (v === "addresses") return go("addresses", {}, false); if (v === "edit_profile") return go("edit_profile", {}, false); if (v === "change_password") return go("change_password", {}, false); if (v === "checkout") return go("checkout", {}, false); if (v === "privacy") return go("privacy", {}, false); if (v === "return") return go("return", {}, false); if (v === "terms") return go("terms", {}, false); if (v === "success") return go("success", {}, false); if (v === "search_home") return go("search_home", {}, false); if (v === "search") return go("search", { q: p.q || "" }, false); if (v === "category") return go("category", { cat: p.cat || "" }, false); if (v === "product") return go("product", { product: p.product || "" }, false); return go("home", {}, false); } async function openAccountEntry(){ try{ const me = await DO.api.fetch("account"); if (me && (me.success === 1 || me.success === true) && me.data && me.data.customer_id) { return go("account", {}, true); } }catch (e) { DO.log.warn("core/app/openAccountEntry", e); } try{ const t = localStorage.getItem("do_refresh_token"); if (t) { const rr = await DO.api.fetch("account/refresh", { method:"POST", data:{ refresh_token: t }}); if (rr && (rr.success === 1 || rr.success === true)) { return go("account", {}, true); } } }catch (e) { DO.log.warn("core/app/openAccountEntry", e); } if (!DO.authModal.open) { await M.loadScripts(["/do/assets/js/components/auth-modal/helpers.js","/do/assets/js/components/auth-modal/phone-google.js","/do/assets/js/components/auth-modal/modal.js"]); await M.loadCss("/do/assets/css/components/auth-modal.css"); } DO.authModal.open("chooser"); } M.go = go; M.handleRoute = handleRoute; M.openAccountEntry = openAccountEntry; })();
Fatal error: Uncaught Error: Class 'Controllerstartuprouter' not found in /home/u996230478/domains/abyatshop.com/public_html/system/storageipsugq8vr1oe/modification/system/engine/action.php:71 Stack trace: #0 /home/u996230478/domains/abyatshop.com/public_html/system/engine/router.php(67): Action->execute(Object(Registry)) #1 /home/u996230478/domains/abyatshop.com/public_html/system/engine/router.php(56): Router->execute(Object(Action)) #2 /home/u996230478/domains/abyatshop.com/public_html/system/framework.php(165): Router->dispatch(Object(Action), Object(Action)) #3 /home/u996230478/domains/abyatshop.com/public_html/system/startup.php(104): require_once('/home/u99623047...') #4 /home/u996230478/domains/abyatshop.com/public_html/index.php(24): start('catalog') #5 {main} thrown in /home/u996230478/domains/abyatshop.com/public_html/system/storageipsugq8vr1oe/modification/system/engine/action.php on line 71